package org.springframework.http.client;

import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;

import java.util.Collections;

import static org.hamcrest.MatcherAssert.assertThat;

/**
 * @author Brian Clozel
 */
public class AbstractMockWebServerTestCase {

    protected static final MediaType textContentType =
            new MediaType("text", "plain", Collections.singletonMap("charset", "UTF-8"));
    protected int port;

    protected String baseUrl;
    private MockWebServer server;

    @Before
    public void setUp() throws Exception {
        this.server = new MockWebServer();
        this.server.setDispatcher(new TestDispatcher());
        this.server.start();
        this.port = this.server.getPort();
        this.baseUrl = "http://localhost:" + this.port;
    }

    @After
    public void tearDown() throws Exception {
        this.server.shutdown();
    }

    protected class TestDispatcher extends Dispatcher {
        @Override
        public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
            try {
                if (request.getPath().equals("/echo")) {
                    assertThat(request.getHeader("Host"),
                            Matchers.containsString("localhost:" + port));
                    MockResponse response = new MockResponse()
                            .setHeaders(request.getHeaders())
                            .setHeader("Content-Length", request.getBody().size())
                            .setResponseCode(200)
                            .setBody(request.getBody());
                    request.getBody().flush();
                    return response;
                }
                else if (request.getPath().equals("/status/ok")) {
                    return new MockResponse();
                }
                else if (request.getPath().equals("/status/notfound")) {
                    return new MockResponse().setResponseCode(404);
                }
                else if (request.getPath().startsWith("/params")) {
                    assertThat(request.getPath(), Matchers.containsString("param1=value"));
                    assertThat(request.getPath(), Matchers.containsString("param2=value1&param2=value2"));
                    return new MockResponse();
                }
                else if (request.getPath().equals("/methods/post")) {
                    assertThat(request.getMethod(), Matchers.is("POST"));
                    String transferEncoding = request.getHeader("Transfer-Encoding");
                    if (StringUtils.hasLength(transferEncoding)) {
                        assertThat(transferEncoding, Matchers.is("chunked"));
                    }
                    else {
                        long contentLength = Long.parseLong(request.getHeader("Content-Length"));
                        assertThat("Invalid content-length",
                                request.getBody().size(), Matchers.is(contentLength));
                    }
                    return new MockResponse().setResponseCode(200);
                }
                else if (request.getPath().startsWith("/methods/")) {
                    String expectedMethod = request.getPath().replace("/methods/", "").toUpperCase();
                    assertThat(request.getMethod(), Matchers.is(expectedMethod));
                    return new MockResponse();
                }
                return new MockResponse().setResponseCode(404);
            }
            catch (Throwable exc) {
                return new MockResponse().setResponseCode(500).setBody(exc.toString());
            }
        }
    }
}
